/**
 * 该文件可自行根据业务逻辑进行调整
 */
import type { AxiosConfirmRequestConfig, RequestClientOptions } from '@croco/plugins/axios';

import { useAppConfig } from '@croco/framework/hooks';
import { preferences } from '@croco/framework/preferences';
import { useUserStore } from '@croco/framework/stores';
import { authenticateResponseInterceptor, defaultResponseInterceptor, errorMessageResponseInterceptor, RequestClient } from '@croco/plugins/axios';

import { ElMessage, ElMessageBox } from 'element-plus';

import { clearStores, refreshToken } from './core';

const { apiURL } = useAppConfig(import.meta.env, import.meta.env.PROD);

function createRequestClient(baseURL: string, options?: RequestClientOptions) {
    const client = new RequestClient({
        ...options,
        baseURL,
    });

    /**
     * 重新认证逻辑
     */
    async function doReAuthenticate(force = false) {
        console.warn('Access token or refresh token is invalid or expired. ');
        const userStore = useUserStore();
        userStore.setLoginUser(null);
        if (preferences.app.loginExpiredMode === 'modal' && userStore.isAccessChecked && !force) {
            userStore.setLoginExpired(true);
        } else {
            // 后端退出接口为了增强安全性需要token验证，故只能正常退出，其他场景通过前端清除token方式重新登录
            await clearStores();
        }
    }

    /**
     * 刷新token逻辑
     */
    async function doRefreshToken() {
        const loginUser = await refreshToken();
        return loginUser ? loginUser.token : '';
    }

    function formatToken(token: null | string) {
        return token ? `Bearer ${token}` : null;
    }

    /**
     * 通过消息弹窗发送请求并决定是否执行（默认发送DELETE请求）
     * @param message 提示内容
     * @param options 配置
     * @param doing 回调函数
     */
    client.addConfirmRequest((config: AxiosConfirmRequestConfig) => {
        ElMessageBox.confirm(config.message, config.title ?? '提示', {
            type: 'warning',
            draggable: true,
            beforeClose: (action, instance, done) => {
                if (action === 'confirm') {
                    instance.title = '正在处理...';
                    instance.confirmButtonLoading = true;
                    service[config.type ?? 'delete'](config.url, config.data)
                        .then(config.success)
                        .catch(config.failure)
                        .finally(() => {
                            instance.confirmButtonLoading = false;
                            done();
                        });
                } else {
                    done();
                }
            },
        }).catch((error) => console.error(error));
    });

    // 请求头处理
    client.addRequestInterceptor({
        fulfilled: async (config) => {
            const userStore = useUserStore();

            config.headers.Authorization = formatToken(userStore.loginUser?.token);
            config.headers['Accept-Language'] = preferences.app.locale;
            return config;
        },
    });

    // 处理返回的响应数据格式
    client.addResponseInterceptor(
        defaultResponseInterceptor({
            codeField: 'code',
            dataField: 'data',
            successCode: 200,
            makeSuccessMessage: ({ message }) => {
                message && ElMessage.success(message);
            },
        }),
    );

    // token过期的处理
    client.addResponseInterceptor(
        authenticateResponseInterceptor({
            client,
            doReAuthenticate,
            doRefreshToken,
            enableRefreshToken: preferences.app.enableRefreshToken,
            formatToken,
        }),
    );

    // 通用的错误处理,如果没有进入上面的错误处理逻辑，就会进入这里
    client.addResponseInterceptor(
        errorMessageResponseInterceptor((msg: string, error) => {
            // 这里可以根据业务进行定制,你可以拿到 error 内的信息进行定制化处理，根据不同的 code 做不同的提示，而不是直接使用 message.error 提示 msg
            // 当前mock接口返回的错误字段是 error 或者 message
            const responseData = error?.response?.data ?? {};
            const errorMessage = responseData?.error ?? responseData?.message ?? '';
            // 如果没有错误信息，则会根据状态码进行提示
            ElMessage.error({
                message: errorMessage || msg,
                grouping: true,
                type: 'error',
            });
        }),
    );

    return client;
}

export const service = createRequestClient(apiURL, {
    responseReturn: 'body',
    headers: {
        'Content-Type': 'application/x-www-form-urlencoded',
    },
    responseType: 'json',
});
// export const client = new RequestClient({ baseURL: apiURL });
